package com.rental.user.service.Impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rental.common.constant.RedisConstant;
import com.rental.common.exception.ProjectException;
import com.rental.common.result.AjaxResult;
import com.rental.common.result.ResultCodeEnum;
import com.rental.common.util.MyJwtUtils;
import com.rental.houses.client.RentalHourseFeign;
import com.rental.houses.client.RequiredHouseFegin;
import com.rental.houses.client.SubletHouseFeignClient;
import com.rental.model.entity.house.RentalHourse;
import com.rental.model.entity.user.UserInfo;
import com.rental.model.form.user.GetRecordForm;
import com.rental.model.form.user.PhoneAndCodeForm;
import com.rental.model.vo.house.HouseTypeVo;
import com.rental.model.vo.house.RequiredHouseVo;
import com.rental.model.vo.house.SubletHousePageVo;
import com.rental.model.vo.user.RecordVo;
import com.rental.quickenPoint.client.UserAccountClient;
import com.rental.user.mapper.UserInfoMapper;
import com.rental.user.service.IUserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;


import java.util.*;
import java.util.concurrent.TimeUnit;


@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements IUserInfoService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private MyJwtUtils myJwtUtils;

    @Autowired
    private SubletHouseFeignClient subletHouseFeignClient;
    @Autowired
    private RequiredHouseFegin requiredHouseFegin;

    @Autowired
    private UserAccountClient userAccountClient;
    @Autowired
    private RentalHourseFeign rentalHourseFeign;


    @Override
    public String sendCode(PhoneAndCodeForm phoneAndCodeForm) {
        //生成验证码
        Random random = new Random();
        int ran = random.nextInt(9000) + 1000;
        String code = String.valueOf(ran);
        System.out.println("生成的验证码为：++++++++++++++++" + code);
        System.out.println(RedisConstant.PHONE_CODE_KEY + phoneAndCodeForm.getPhone());
        //将验证码存入redis
        redisTemplate.opsForValue().set(RedisConstant.PHONE_CODE_KEY + phoneAndCodeForm.getPhone(), code, 5, TimeUnit.MINUTES);
        // todo 测试时不发送短信
//        try {
//            SmsUtils.sendMessage(code,userInfo.getPhone());
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        }
        return code;
    }

    @Override
    public String login(PhoneAndCodeForm phoneAndCodeForm) {
        // 验证表单数据
        if (phoneAndCodeForm == null || StringUtils.isBlank(phoneAndCodeForm.getPhone()) || StringUtils.isBlank(phoneAndCodeForm.getCode())) {
            throw new ProjectException(ResultCodeEnum.LOGIN_NULL);
        }
        // 判断验证码是否正确
        Object o = redisTemplate.boundValueOps(RedisConstant.PHONE_CODE_KEY + phoneAndCodeForm.getPhone()).get();
        if (o == null) throw new ProjectException(ResultCodeEnum.VALIDATE_CODE_NOT_EXIST);
        String code = o.toString();
        if (code == null || !code.equals(phoneAndCodeForm.getCode()))
            throw new ProjectException(ResultCodeEnum.VALIDATE_CODE_ERROR);
        // 删除验证码
        redisTemplate.delete(RedisConstant.PHONE_CODE_KEY + phoneAndCodeForm.getPhone());
        // 账号是否存在
        LambdaQueryWrapper<UserInfo> eq = Wrappers.lambdaQuery(UserInfo.class).eq(UserInfo::getPhone, phoneAndCodeForm.getPhone());
        UserInfo userInfo = userInfoMapper.selectOne(eq);
        if (userInfo == null) {
            // 注册
            userInfo = new UserInfo();
            userInfo.setNickName("用户" + this.randomString()); // 随机生成用户名
            userInfo.setPhone(phoneAndCodeForm.getPhone());
            userInfo.setPhoto("https://b0.bdstatic.com/05a74896aaeef4a08074d1a04a2e8954.jpg@h_1280");
            userInfo.setIsWxMsg(1);
            userInfo.setIsNote(1);
            if (!this.save(userInfo)) throw new ProjectException(ResultCodeEnum.REGISTER_ERROR);
            // 初始化用户账户
            AjaxResult<Boolean> initUserAccount = userAccountClient.initUserAccount(userInfo.getId());
            if (!initUserAccount.getData()) throw new ProjectException(ResultCodeEnum.REGISTER_ERROR);
        }
        // 生成token
        return myJwtUtils.generateToken(userInfo.getId() + "");
    }

    private StringBuilder randomString() {
        StringBuilder result = new StringBuilder();
        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();
        for (int i = 0; i < 7; i++) {
            int index = random.nextInt(str.length());
            result.append(str.charAt(index));
        }
        return result;
    }

    @Override
    public UserInfo getUserInfo(String token) {
        Long id = Long.valueOf(myJwtUtils.parseToken(token));
        UserInfo userInfo = this.getById(id);
        System.out.println("userInfo:" + userInfo);
        return userInfo;
    }

    /**
     * 获取浏览记录
     *
     * @param getRecordForm 请求表单
     * @return 浏览记录
     */
    @Override
    public RecordVo getBrowseRecord(GetRecordForm getRecordForm) {
        // 获取浏览记录的zset
        BoundZSetOperations<String, HouseTypeVo> zSetOps = redisTemplate.boundZSetOps(RedisConstant.USER_VISIT_HISTORY_KEY + getRecordForm.getId());

        // 获取请求的每页数量和起始位置
        Integer resultSize = getRecordForm.getSize();
        Integer start = resultSize * (getRecordForm.getPage() - 1);
        // 是否隐藏下架的记录
        Integer state = getRecordForm.getState();

        // 最终结果
        List<String> result = new ArrayList<>();
        // 临时存储zset数据
        Set<ZSetOperations.TypedTuple<HouseTypeVo>> tempList = new LinkedHashSet<>();
        // 计算当前遍历的有效个数
        int count = 0;

        Long size = zSetOps.size();
        try {
            for (long l = 0L; l < size; l++) {
                // 移出并获取最大score的元素，存入临时zset集合
                ZSetOperations.TypedTuple<HouseTypeVo> typedTuple = zSetOps.popMax();
                tempList.add(typedTuple);
                HouseTypeVo value = typedTuple.getValue();

                // 判断类型，获取对应的记录
                Integer type = value.getType();
                // 用于存储记录的JSON字符串
                String jsonStr = "";

                if (type == 1) {
                    // 调用出租房屋远程接口获取出租房屋信息
                    RentalHourse data = rentalHourseFeign.getRentalHoursePage(value.getId(), state).getData();
                    if (data != null ) {
                        count++;
                        jsonStr = JSONObject.toJSONString(data);
                    }
//                    else {
//                        // 已删除的记录，从临时zset集合中移除
//                        tempList.remove(typedTuple);
//                    }
                } else if (type == 2) {
                    // 调用求租房屋远程接口获取求租房屋信息
                    AjaxResult<SubletHousePageVo> subletHousePageVo = subletHouseFeignClient.getSubletHousePageVo(value.getId(), state);
                    // 如果数据不为空，则为有效数据
                    if (subletHousePageVo.getData() != null) {
                        count++;
                        jsonStr = JSONObject.toJSONString(subletHousePageVo.getData());
                    }
//                    else {
//                        // 已删除的记录，从临时zset集合中移除
//                        tempList.remove(typedTuple);
//                    }
                } else if (type == 3) {
                    //  调用求租房屋远程接口获取求租房屋信息
                    AjaxResult<RequiredHouseVo> requiredHouseDetail = requiredHouseFegin.getRequiredHouseDetail(value.getId());
                    if (requiredHouseDetail.getData() != null) {
                        count++;
                        jsonStr = JSONObject.toJSONString(requiredHouseDetail.getData());
                    }
//                    else {
//                        // 已删除的记录，从临时zset集合中移除
//                        tempList.remove(typedTuple);
//                    }
                }

                if (StringUtils.isNotBlank(jsonStr) && count > start) {
                    result.add(jsonStr);
                    if (result.size() == resultSize) break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 将临时zset集合中的数据重新存入zset
            if (tempList.size() > 0) {
                zSetOps.add(tempList);
            }
        }
        return new RecordVo(result, size);
    }

    /**
     * 获取收藏信息
     *
     * @param getRecordForm 请求表单
     * @return 收藏信息
     */
    @Override
    public RecordVo getCollectInfo(GetRecordForm getRecordForm) {
        // 获取浏览记录的zset
        BoundZSetOperations<String, HouseTypeVo> zSetOps = redisTemplate.boundZSetOps(RedisConstant.USER_COLLECTION_KEY + getRecordForm.getId());

        // 获取请求的每页数量和起始位置
        Integer resultSize = getRecordForm.getSize();
        Integer start = resultSize * (getRecordForm.getPage() - 1);
        // 是否隐藏下架的记录
        Integer state = getRecordForm.getState();

        // 最终结果
        List<String> result = new ArrayList<>();
        // 临时存储zset数据
        Set<ZSetOperations.TypedTuple<HouseTypeVo>> tempList = new LinkedHashSet<>();
        // 计算当前遍历的有效个数
        int count = 0;

        Long size = zSetOps.size();
        try {
            for (long l = 0L; l < size; l++) {
                // 移出并获取最大score的元素，存入临时zset集合
                ZSetOperations.TypedTuple<HouseTypeVo> typedTuple = zSetOps.popMax();
                tempList.add(typedTuple);
                HouseTypeVo value = typedTuple.getValue();

                // 判断类型，获取对应的记录
                Integer type = value.getType();
                // 用于存储记录的JSON字符串
                String jsonStr = "";

                if (type == 1) {
                    // 调用出租房屋远程接口获取出租房屋信息
                    RentalHourse data = rentalHourseFeign.getRentalHoursePage(value.getId(), state).getData();
                    if (data != null ) {
                        count++;
                        jsonStr = JSONObject.toJSONString(data);
                    }
//                    else {
//                        // 已删除的记录，从临时zset集合中移除
//                        tempList.remove(typedTuple);
//                    }
                } else if (type == 2) {
                    // 调用求租房屋远程接口获取求租房屋信息
                    AjaxResult<SubletHousePageVo> subletHousePageVo = subletHouseFeignClient.getSubletHousePageVo(value.getId(), state);
                    // 如果数据不为空，则为有效数据
                    if (subletHousePageVo.getData() != null) {
                        count++;
                        jsonStr = JSONObject.toJSONString(subletHousePageVo.getData());
                    }
//                    else {
//                        // 已删除的记录，从临时zset集合中移除
//                        tempList.remove(typedTuple);
//                    }
                } else if (type == 3) {
//                    //  调用求租房屋远程接口获取求租房屋信息
                    AjaxResult<RequiredHouseVo> requiredHouseDetail = requiredHouseFegin.getRequiredHouseDetail(value.getId());
                    if (requiredHouseDetail.getData() != null) {
                        count++;
                        jsonStr = JSONObject.toJSONString(requiredHouseDetail.getData());
                    }
//                    else {
//                        // 已删除的记录，从临时zset集合中移除
//                        tempList.remove(typedTuple);
//                    }
                }

                if (StringUtils.isNotBlank(jsonStr) && count > start) {
                    result.add(jsonStr);
                    if (result.size() == resultSize) break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 将临时zset集合中的数据重新存入zset
            if (tempList.size() > 0) {
                zSetOps.add(tempList);
            }
        }
        return new RecordVo(result, size);
    }

    /**
     * 获取用户发布信息
     *
     * @param getRecordForm 请求表单
     * @return 发布信息
     */
    @Override
    public RecordVo getPublish(GetRecordForm getRecordForm) {
        // 获取浏览记录的zset
        BoundZSetOperations<String, HouseTypeVo> zSetOps = redisTemplate.boundZSetOps(RedisConstant.USER_PUBLISH_KEY + getRecordForm.getId());

        // 获取请求的每页数量和起始位置
        Integer resultSize = getRecordForm.getSize();
        Integer start = resultSize * (getRecordForm.getPage() - 1);
        System.out.println("计算得到的 start"+start+"page"+getRecordForm.getPage()+"size"+resultSize);
        // 是否隐藏下架的记录
        Integer state = getRecordForm.getState();

        // 最终结果
        List<String> result = new ArrayList<>();
        // 临时存储zset数据
        Set<ZSetOperations.TypedTuple<HouseTypeVo>> tempList = new LinkedHashSet<>();
        // 计算当前遍历的有效个数
        int count = 0;

        Long size = zSetOps.size();

        try {
            for (long l = 0L; l < size; l++) {
                // 移出并获取最大score的元素，存入临时zset集合
                ZSetOperations.TypedTuple<HouseTypeVo> typedTuple = zSetOps.popMax();
                tempList.add(typedTuple);
                HouseTypeVo value = typedTuple.getValue();

                // 判断类型，获取对应的记录
                Integer type = value.getType();
                // 用于存储记录的JSON字符串
                String jsonStr = "";
                System.out.println(value);
                if (type == 1) {
                    // 调用出租房屋远程接口获取出租房屋信息
                    RentalHourse data = rentalHourseFeign.getRentalHoursePage(value.getId(), state).getData();
                    if (data != null ) {
                        count++;
                        jsonStr = JSONObject.toJSONString(data);
                    }
//                    else {
//                        // 已删除的记录，从临时zset集合中移除
//                        tempList.remove(typedTuple);
//                    }
                } else if (type == 2) {
                    // 调用求租房屋远程接口获取求租房屋信息
                    AjaxResult<SubletHousePageVo> subletHousePageVo = subletHouseFeignClient.getSubletHousePageVo(value.getId(), state);
                    // 如果数据不为空，则为有效数据
                    if (subletHousePageVo.getData() != null) {
                        count++;
                        jsonStr = JSONObject.toJSONString(subletHousePageVo.getData());
                    }
//                    else {
//                        // 已删除的记录，从临时zset集合中移除
//                        tempList.remove(typedTuple);
//                    }
                } else if (type == 3) {
                    // 调用求租房屋远程接口获取求租房屋信息
                    AjaxResult<RequiredHouseVo> requiredHouseDetail = requiredHouseFegin.getRequiredHouseDetail(value.getId());
                    System.out.println("Actual JSON response: " + JSONObject.toJSONString(requiredHouseDetail));
                    if (requiredHouseDetail.getData() != null) {
                        count++;
                        jsonStr = JSONObject.toJSONString(requiredHouseDetail.getData());
                        System.out.println("count 增加后的值: {}"+count);

                    }
//                    else {
//                        // 已删除的记录，从临时zset集合中移除
//                        tempList.remove(typedTuple);
//                    }
                }
                System.out.println("count:"+count+"start:"+start+"resultSize:"+resultSize);

                if (StringUtils.isNotBlank(jsonStr) && count > start) {
                    System.out.println("满足条件，添加数据到 result"+jsonStr+"count"+count+"start"+start);
                    result.add(jsonStr);
                    if (result.size() == resultSize) break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 将临时zset集合中的数据重新存入zset
            if (tempList.size() > 0) {
                zSetOps.add(tempList);
            }
        }


        System.out.println("最终返回的 result: "+result+"size:"+size);
        return new RecordVo(result, size);
    }

    @Override
    public Long countBannedUser() {
        return this.baseMapper.countBannedUser();
    }

}
